package com.hpe.controller.student;

import com.github.pagehelper.PageInfo;
import com.hpe.common.Const;
import com.hpe.pojo.*;
import com.hpe.service.*;
import com.hpe.util.ServerResponse;
import com.hpe.util.TokenProcessor;
import com.hpe.util.ToolUtil;
import com.hpe.vo.AnswerSheet;
import com.hpe.vo.PaperInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.ParseException;
import java.util.*;

/**
 * Created by chunjie on 2017/9/26.
 */
@Controller
@RequestMapping("/student/exam")
public class StudentExamController {

    private Logger logger = LoggerFactory.getLogger(StudentExamController.class);

    @Autowired
    private StudentInfoService studentInfoService;

    // 注入 test业务类,testService是指试卷，paperService是指答卷！
    @Autowired
    private ExamService testService;

    @Autowired
    private QuestionService questionService;

    @Autowired
    private ScoreService paperService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private SClassService stuClassService;

    @Autowired
    private BigQuestionService bigQuestionService;

    /**
     * @Author:TangWenhao
     * @Description:显示待考试试卷
     * @Date:17:22 2017/9/25
     */
    @RequestMapping(method = RequestMethod.POST, value = "/show_papers.do")
    @ResponseBody
    public ServerResponse<PageInfo> showPapers(HttpSession session, @RequestParam(name = "pageNum", defaultValue = "1") int pageNum,
                                               @RequestParam(name = "pageSize", defaultValue = "3") int pageSize) throws ParseException {
        // 获取数据集合
        // 通过session获取id
        Student student = (Student) session.getAttribute(Const.CURRENT_STUDENT);
        int stuId = student.getId();
        // 数据量有点大，效率比较低，请注意后续优化。
        ServerResponse<PageInfo> response = testService.findListByStuId(stuId, pageNum, pageSize);
        List<PaperInfo> testList = response.getData().getList();
        // 移除 集合中的 数据。
        List removeList = new ArrayList();
        for (PaperInfo paper : testList) {
            int testId = paper.getId();
            // 过滤 已经考过的试卷，不在页面显示
            List<Score> ifhaveList = paperService.getPaperByStudentId(Integer.valueOf(stuId), testId);
            if (ifhaveList.size() > 0) {
                if (ifhaveList.get(0).getTime() != null) {
                    removeList.add(paper);
                    continue;
                }
            }
            // 过滤 试卷考试失效已过。
            // 获取 考试开始时间
            long startTime = paper.getStarttime().getTime();
            // 根据 当前时间，计算 剩余时间。 + 考试时长
            Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
            long curtime = calendar.getTimeInMillis();// 当前时间毫秒
            long diff = startTime + (int) paper.getTestTime() * 60 * 1000 - curtime;
            if (diff < 0) { //为负数，说明，截至时间已到。
                removeList.add(paper);
                continue;
            }
        }
        response.getData().getList().removeAll(removeList); // 从testList中移除已经考过的试卷。
        return response;
    }

    /**
    * @Author:TangWenhao
    * @Description: 考试倒计时判断
    * @Date:19:58 2017/11/14
    */
    @RequestMapping(method = RequestMethod.GET, value = "/exam_left_time.do")
    @ResponseBody
    public ServerResponse examStartOrNot(int examId) throws ParseException {
        Exam exam = testService.selectByPrimaryKey(examId).getData();
        Date startDate = exam.getStarttime();
        long curtime = new Date().getTime();// 当前时间毫秒
        long starttime = startDate.getTime();// 考试时间 毫秒
        if (curtime < starttime) {
            return ServerResponse.createByError();
        }
        return ServerResponse.createBySuccess();
    }

    /**
     * @Author:TangWenhao
     * @Description:开始考试学生试卷生成。
     * @Date:18:45 2017/9/25
     */
    @RequestMapping(method = RequestMethod.GET, value = "/stu_exam.do")
    @ResponseBody
    public ModelAndView stuExam(HttpSession session, @RequestParam("examid") String examid, ModelAndView mv) throws ParseException {
        // 获取test试卷id
        // 根据id查询试卷信息
        ServerResponse<Exam> response = testService.selectByPrimaryKey(Integer.valueOf(examid));
        Exam test = response.getData();
        // 验证 日期是否过时
        // 获取 考试时间
        if (test == null) {
            //转发到主页
            mv.setViewName("redirect:/stu_index.do");
            return mv;
        }
        Date startTime = test.getStarttime();
        // 根据 当前时间，计算 剩余时间  + 考试时长。
        int testTime = test.getTesttime(); // 分钟
        int examtime = testTime * 60 * 1000; // 考试时长 毫秒

        long curtime = System.currentTimeMillis();// 当前时间毫秒
        Calendar calendar1 = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        calendar1.setTime(startTime);
        long starttime = calendar1.getTimeInMillis();// 考试时间 毫秒
        // 时间差
        long diff = starttime - curtime + examtime;// 是否属于考试区间
        // 考试已经结束
        if (diff < 0) {
            //转发到用户首页。
            mv.setViewName("redirect:/stu_index.do");
            return mv;
        }
        // 时间 在 正式考试期间；直接显示考试页面，并且剩余时间计时；否则转发到一个倒计时开始的界面exmaview.jsp。
        // 考试时间的毫秒数 小于 （未到考试时间）进入倒计时。。。。
        if (curtime < starttime) {
            // 计算剩余的 天，小时，分，秒 集合。
            Map timeMap = ToolUtil.getDayHourSe(starttime - curtime);
            //转到倒计时/student/exam/examview.jsp页面
            mv.addObject("timeMap", timeMap);
            mv.addObject("examid", examid);
            mv.setViewName("/stu-examview");
            return mv;
        }

        // 计算剩余考试时间。时长 减去 已考时长。（examtime - （curtime - statrtime））
        Map timeMap = ToolUtil.getDayHourSe(examtime - (curtime - starttime));
        mv.addObject("timeMap", timeMap);
        String ques = test.getQuestions(); // 题目主键的字符串 2,3,4,5;12,1,3;123,123,1===> [2,3,4,5]
        String[] typesQue = ques.split(";");
        // 根据test试卷 questions , 查询单选题。
        List queList = questionService.findByIdsForStu(typesQue[0].split(","));
        //  查询  简答题 或 编程题。
        List que1List = new ArrayList();
        if (typesQue.length >= 2 && typesQue[1].length() >= 1) {
            que1List = bigQuestionService.findBigQuesByIds(typesQue[1].split(","), 1);
        }
        List que2List = new ArrayList();//编程题。
        if (typesQue.length >= 3 && typesQue[2].length() >= 1) {
            que2List = bigQuestionService.findBigQuesByIds(typesQue[2].split(","), 2);
        }

        // 通过session获取当前登录学生的id
        // 通过session获取id
        Student student = (Student) session.getAttribute(Const.CURRENT_STUDENT);
        StudentInfo studentInfo = studentInfoService.selectByKey(student.getId());
        // 回显班级 和 课程名
        Course c = courseService.getCourseById(test.getCourseid());
        SClass stuclass = stuClassService.findStuClassById(Integer.parseInt(studentInfo.getSpare()));

        // todo HtmlUtils!!
        //需要对单选、简答以及编程进行重新赋值
        // 回显到 exam.jsp页面
        mv.addObject("test", test);
        mv.addObject("queList", queList);
        mv.addObject("queListSize", queList == null ? 0 : queList.size());
        mv.addObject("queList1", que1List);
        mv.addObject("queListSize1", que1List == null ? 0 : que1List.size());
        mv.addObject("queList2", que2List);
        mv.addObject("queListSize2", que2List == null ? 0 : que2List.size());
        mv.addObject("course", c);
        mv.addObject("stuClass", stuclass);

        mv.addObject("stuName", studentInfo.getName());
        mv.addObject("newId", studentInfo.getNewId());
        // 防止重复提交。
        String token = TokenProcessor.getInstance().getToken();//创建令牌
        //////////.println("在FormServlet中生成的token："+token);
        session.setAttribute("token", token);  //在服务器使用session保存token(令牌)
        mv.setViewName("stu-examing");
        return mv;
    }

    /**
     * @Author:TangWenhao
     * @Description:提交试卷,// TODO: 2017/9/25
     * @Date:18:46 2017/9/25
     */
    @RequestMapping(method = RequestMethod.POST, value = "/exam_submit.do")
    @ResponseBody
    public ServerResponse submitExam(HttpSession session, HttpServletRequest req, AnswerSheet answerSheet, ModelAndView mv) {
        // 令牌处理，防止重复提交。
        boolean b = isRepeatSubmit(req);//判断用户是否是重复提交
        if (b == true) {
            ////////.println("请不要重复提交");
            mv.setViewName("stu-ehistory");
            return ServerResponse.createByErrorMsg("请不要重复提交");
        }
        session.removeAttribute("token");//移除session中的token
        // 通过session获取id
        Student student = (Student) session.getAttribute(Const.CURRENT_STUDENT);
        int courseId = answerSheet.getCourseId();
        Double scores = answerSheet.getScores();
        Double score = answerSheet.getScore();
        Double score1 = answerSheet.getScore1();
        Double score2 = answerSheet.getScore2();
        int testId = answerSheet.getTestId();
        String countTime = answerSheet.getCountTime();
        //限制根据URL再次提交
        Score p = paperService.findById(student.getId(), Integer.valueOf(testId));
        if(p.getTime()!=null){
            return ServerResponse.createByErrorMsg("请不要重复提交");
        }
        // 获取当前所有的试题的主键id 数组。循环遍历数组  id+ "_choice"
        String[] ids = answerSheet.getId();
        // 答题选项 封装到map对象中
        Map<Integer, String> stuAnsMap = new HashMap<Integer, String>();
        for (int i = 0; i < ids.length; i++) {
            String id = ids[i];
            //获取所有的 todo
            String stuAns = req.getParameter(id + "_choice");
            // 把答题的 选项 按照 {key:value}={主键id：选项ABCD} 封装到一个Map对象中。
            stuAnsMap.put(Integer.parseInt(id), stuAns);
            //resp.getWriter().println(i + 1 + "=" + stuAns);
        }

        // 根据testID查询试卷信息。或者 表单 提交了所有 question的id。
        // 根据testId 查询 试卷的questions.
        List<Questions> questionList = questionService.findByIds(ids);
        // 遍历 questionList中的正确答案，通过stuAnsMap中的答题选项对比。
        // 错误答案的集合
        List worngAns = new ArrayList();
        // 错题主键id的集合
        List worngIds = new ArrayList();

        for (Questions que : questionList) {
            // 正确答案，和que的主键id； 然后和stuAnsMap对比。
            String stuAns = stuAnsMap.get(que.getId());// 学生的选项
            String ans = que.getAns();    // 标准答案
            if (!ans.equalsIgnoreCase(stuAns)) {// 忽略大小写 比对值。
                // 答错的了;把stuAns变量放置到错误答案集合中。
                worngAns.add(stuAns);
                worngIds.add(que.getId());
            }
        }
        // 封装到答卷实体类中。同时计算分值。

        p.setCreatedate(new Date());
        // 错题主键集合 字符串类型 “，”号隔开
        String tmp = Arrays.toString(worngIds.toArray());
        p.setWrongqueid(tmp.substring(1, tmp.length() - 1));
        // 正确答案集合
        String tmpAns = Arrays.toString(worngAns.toArray());
        p.setWrongans(tmpAns.substring(1, tmpAns.length() - 1));
        p.setTime(ToolUtil.getDateDif(Long.valueOf(countTime) * 1000));// 答卷时长

        // 获取 试卷 分数 ；获取错题集合； 获取正确答案集合。
        // 总分scores - （总分/试题数）* 错题的个数
        double sco = (Double.valueOf(score).doubleValue()) -
                Double.valueOf(score) / ids.length * worngAns.size();
        p.setScore1(sco);
        //总成绩现在为单选成绩
        p.setScoreB(sco);
        //************************增加 简答和编程 字段。
        // 获取简答和编程题的主键集合
        String[] queIds1 = answerSheet.getQueId1();
        String[] queIds2 = answerSheet.getQueId2();
        //新建StringBuffer,存取所有的主观题id
        StringBuffer Ids = new StringBuffer();
        //获取简单题的题目和学生答案
        String contentTitle = "";
        String contentAns = "";
        if (queIds1 != null && queIds1.length > 0) {
            for (int i = 0; i < queIds1.length; i++) {
                String queId = queIds1[i];
                //每道题的两边都加上‘,’
                Ids.append(",," + queId + ",");

                String queTitle = req.getParameter(queId + "_contentTitle");
                String queAns = req.getParameter(queId + "_area");
                if (queAns == null || queAns.equals("")) {
                    queAns = "未完成";
                }

                //调用工具类中的删除特殊字符方法，删除特殊字符("~","@@@","/")
                queTitle = ToolUtil.delSpecialChar(queTitle);
                queAns = ToolUtil.delSpecialChar(queAns);
                // queTitle，queTitle，queTitle，
                contentTitle += queTitle + "~";
                contentAns += queAns + "~";
            }
        }
        contentTitle += "@@@";
        contentAns += "@@@";

        if (queIds2 != null && queIds2.length > 0) {
            for (int i = 0; i < queIds2.length; i++) {
                String queId = queIds2[i];
                //每道题的两边都加上‘,’
                Ids.append(",," + queId + ",");

                String queTitle = req.getParameter(queId + "_contentTitle");
                String queAns = req.getParameter(queId + "_area");
                if (queAns == null || queAns.equals("")) {
                    queAns = "未完成";
                }
                //调用工具类中的删除特殊字符方法，删除特殊字符("~","@@@","/")
                queTitle = ToolUtil.delSpecialChar(queTitle);
                queAns = ToolUtil.delSpecialChar(queAns);
                contentTitle += queTitle + "~";
                contentAns += queAns + "~";
            }
        }
        //将ids保存到数据库中
        //System.out.println("Ids:"+Ids.toString());
        p.setSpare("0");
        p.setBigqueids(Ids.toString());
        if(p.getBigqueids()==null||"".equals(p.getBigqueids())){
            if(p.getStatus()==null){
                p.setStatus(1);
            }else{
                p.setStatus(1+p.getStatus());// 已经阅完。
            }
        }
        p.setSpare1(p.getBigqueids());
        p.setContentans(contentAns);
        p.setContenttitl(contentTitle);
        // 保存到数据，并且在页面显示学生分数；及错题的个数。
        paperService.updatePagers(p);
        session.invalidate();
        HttpSession session1 = req.getSession();
        session1.setAttribute(Const.CURRENT_STUDENT, student);
        return ServerResponse.createBySuccess();
    }

    private boolean isRepeatSubmit(HttpServletRequest request) {
        String client_token = request.getParameter("token");
        //1、如果用户提交的表单数据中没有token，则用户是重复提交了表单
        if (client_token == null) {
            return true;
        }
        //取出存储在Session中的token
        String server_token = (String) request.getSession().getAttribute("token");
        //2、如果当前用户的Session中不存在Token(令牌)，则用户是重复提交了表单
        if (server_token == null) {
            return true;
        }
        //3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同，则用户是重复提交了表单
        if (!client_token.equals(server_token)) {
            return true;
        }
        return false;
    }

    /**
     * @Author:TangWenhao
     * @Description:临时保存答案至session
     * @Date:17:12 2017/9/28
     */
    @RequestMapping(method = RequestMethod.GET, value = "/save_papers.do")
    @ResponseBody
    public void savePapers(HttpSession session, @RequestParam("index") String index,
                           @RequestParam("value") String value) {
        session.setAttribute(index, value);
    }
}
